﻿using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Resources;

namespace DynamicallyBuildUDFBasedOnSchema
{
	class Compilation
	{
		public static bool Compile(bool isToDisk)
		{
			List<SyntaxTree> trees = new List<SyntaxTree>();
			ResourceSet rs = Properties.Resources.ResourceManager.GetResourceSet(CultureInfo.CurrentCulture, true, true);
			foreach (DictionaryEntry de in rs)
			{
				//				Console.WriteLine("Loading code {0}.cs.", de.Key.ToString());
				trees.Add(SyntaxFactory.ParseSyntaxTree(de.Value.ToString()));
			}

			DirectoryInfo di = new DirectoryInfo(".");
			foreach (FileInfo fi in di.GetFiles("*.cs", SearchOption.TopDirectoryOnly))
			{
				using (StreamReader sr = new StreamReader(fi.FullName))
				{
					Console.WriteLine("Loading code {0}.", fi.Name);
					trees.Add(SyntaxFactory.ParseSyntaxTree(sr.ReadToEnd()));
				}
			}

			Console.WriteLine();
			Console.Write("Compiling to {0}...", isToDisk ? "disk" : "memory");
			return compileCode(trees, isToDisk);
		}

		static bool compileCode(List<SyntaxTree> trees, bool isToDisk)
		{
			string runtimePath = Environment.GetEnvironmentVariable("SystemRoot") + @"\Microsoft.NET\Framework64\v4.0.30319\{0}.dll";
			IEnumerable<MetadataReference> defaultReferences =
			new[]
			{
				MetadataReference.CreateFromFile(string.Format(runtimePath, "mscorlib")),
				MetadataReference.CreateFromFile(string.Format(runtimePath, "System")),
				MetadataReference.CreateFromFile(string.Format(runtimePath, "System.Core")),
				MetadataReference.CreateFromFile(string.Format(runtimePath, "System.DirectoryServices")),
				MetadataReference.CreateFromFile(string.Format(runtimePath, "System.DirectoryServices.Protocols")),
				MetadataReference.CreateFromFile(string.Format(runtimePath, "System.Data")),
				MetadataReference.CreateFromFile(string.Format(runtimePath, "System.Xml")),
			};

			CSharpCompilation access = CSharpCompilation.Create("ActiveDirectoryProxy.dll", trees, defaultReferences
				, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary).WithOverflowChecks(true).WithOptimizationLevel(OptimizationLevel.Release));

			EmitResult res = null;
			Stream output = null;
			if (isToDisk)
			{
				output = new FileStream("ActiveDirectoryProxy.dll", FileMode.Create, FileAccess.Write, FileShare.None);
			}
			else
			{
				output = new MemoryStream();
			}

			try
			{
				res = access.Emit(output);
			}
			finally
			{
				if (output != null)
				{ ((IDisposable)output).Dispose(); }
			}

			Console.WriteLine(res.Success ? "Success!" : "Failed");
			if (!res.Success)
			{
				foreach (Diagnostic d in res.Diagnostics)
				{
					if (d.Severity == DiagnosticSeverity.Error)
					{
						Console.WriteLine("{0} - {1}", d.Id, d);
					}
				}
			}

			return res.Success;
		}
	}
}
